/* Copyright (c) 2022-2022, LiWangQian<liwangqian@huawei.com> All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "libcfgm/file.h"
#include "libcfgm/error.h"
#include <stddef.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

bool cfgm_file_exist(const char *file)
{
    return (file != NULL) && (access(file, F_OK) == 0);
}

bool cfgm_file_readable(const char *file)
{
    return (file != NULL) && (access(file, R_OK) == 0);
}

bool cfgm_file_writable(const char *file)
{
    return (file != NULL) && (access(file, W_OK) == 0);
}

bool cfgm_file_excutable(const char *file)
{
    return (file != NULL) && (access(file, X_OK) == 0);
}

bool cfgm_file_rwable(const char *file)
{
    return (file != NULL) && (access(file, W_OK | R_OK) == 0);
}

unsigned int cfgm_file_size(const char *file)
{
    if (file == NULL) {
        return 0;
    }

    FILE *fp = fopen(file, "r");
    if (fp == NULL) {
        return 0;
    }

    (void)fseek(fp, 0, SEEK_END);
    long int size = ftell(fp);
    fclose(fp);
    return (unsigned int)size;
}

const char *cfgm_file_extension(const char *file)
{
    if (file == NULL) {
        return NULL;
    }

    const char *pdot = strrchr(file, '.');
    return pdot ? pdot + 1 : NULL_EXTENSION;
}

int cfgm_file_read(const char *file, cfgm_string_t *out)
{
    if (file == NULL || !cfgm_string_valid(out)) {
        return CFGM_EPARAM;
    }

    unsigned int read_bytes = cfgm_string_available_size(out);
    if (read_bytes == 0) {
        return CFGM_EPARAM;
    }

    FILE *fp = fopen(file, "r");
    if (fp == NULL) {
        return CFGM_EEXIST;
    }

    size_t nbytes = fread(out->buf + out->size, sizeof(char), read_bytes, fp);
    (void)fclose(fp);
    if (nbytes == 0) {
        return CFGM_EFILE;
    }

    out->size += nbytes;
    return CFGM_OK;
}

#ifdef __cplusplus
}
#endif
